package DyingBaby.backend.catalog;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.lang.reflect.Type;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

/**
 * 数据库目录管理器（元数据管理器）
 * 负责管理数据库中所有表的结构信息（元数据），包括表的创建、查询和持久化存储
 * 使用JSON文件作为元数据的存储格式，通过Gson库进行序列化和反序列化
 */
public class Catalog {
    private static final String DATA_DIR = "data"; // 数据目录名称，用于存储数据库文件
    private static final String CATALOG_FILE = "catalog.json"; // 目录文件名称，存储表结构信息

    private final Gson gson = new Gson(); // Gson实例用于JSON序列化和反序列化
    private final Path catalogPath; // 元数据文件的完整路径
    private final Map<String, TableSchema> tables = new HashMap<>(); // 内存中的表结构缓存：表名 -> 表结构映射

    /**
     * 构造函数：初始化数据库目录
     * 1. 检查数据目录是否存在，不存在则创建
     * 2. 设置目录文件的完整路径
     * 3. 加载已有的表结构信息到内存
     */
    public Catalog() {
        try {
            // 获取数据目录路径
            Path dataDir = Paths.get(DATA_DIR);
            // 如果数据目录不存在，则创建
            if (!Files.exists(dataDir)) {
                Files.createDirectories(dataDir);
            }
            // 设置完整的元数据文件路径
            this.catalogPath = dataDir.resolve(CATALOG_FILE);
            // 加载已有的表结构信息
            load();
        } catch (Exception e) {
            throw new RuntimeException("Init catalog failed", e);
        }
    }

    /**
     * 创建新表
     * @param schema 表结构对象
     * @throws IllegalArgumentException 如果表已存在
     */
    public synchronized void createTable(TableSchema schema) {
        String name = schema.getTableName();
        // 检查表是否已存在
        if (tables.containsKey(name)) {
            throw new IllegalArgumentException("Table exists: " + name);
        }
        // 将表结构添加到内存缓存
        tables.put(name, schema);
        // 持久化到磁盘
        persist();
    }

    /**
     * 获取指定表的结构信息
     * @param tableName 表名
     * @return 表结构对象
     * @throws IllegalArgumentException 如果表不存在
     */
    public synchronized TableSchema getTable(String tableName) {
        TableSchema ts = tables.get(tableName);
        if (ts == null) {
            throw new IllegalArgumentException("Table not found: " + tableName);
        }
        return ts;
    }

    /**
     * 获取所有表的结构信息
     * @return 不可修改的表结构映射副本
     */
    public synchronized Map<String, TableSchema> listTables() {
        return Collections.unmodifiableMap(tables);
    }

    /**
     * 从磁盘加载元数据信息到内存
     * 如果元数据文件不存在则跳过加载
     */
    private void load() {
        try {
            File file = catalogPath.toFile();
            // 检查元数据文件是否存在
            if (!file.exists()) {
                return;
            }
            // 读取并解析JSON文件
            try (FileReader fr = new FileReader(file)) {
                // 定义Gson解析类型
                Type type = new TypeToken<Map<String, TableSchema>>(){}.getType();
                Map<String, TableSchema> loaded = gson.fromJson(fr, type);
                // 将加载的数据放入内存缓存
                if (loaded != null) {
                    tables.clear();
                    tables.putAll(loaded);
                }
            }
        } catch (Exception e) {
            throw new RuntimeException("Load catalog failed", e);
        }
    }

    /**
     * 将内存中的元数据信息持久化到磁盘
     * 使用JSON格式存储
     */
    private void persist() {
        try (FileWriter fw = new FileWriter(catalogPath.toFile())) {
            gson.toJson(tables, fw);
        } catch (Exception e) {
            throw new RuntimeException("Persist catalog failed", e);
        }
    }
} 